package com.personal.datacompare.tree;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.personal.core.data.DataTable;

/**]
 * 树
 * @author cuibo
 *
 * @param <T>
 * @param <V>
 */
public abstract class ITree<T, V> implements Serializable
{
    /**
     *
     */
    private static final long serialVersionUID = 4635080669514304300L;
    /** 数据源 */
    protected T source;
    /** 子集合 */
    protected List<ITreeNode<T, V>> childs;

    public ITree()
    {
    }

    public ITree(T source)
    {
        this.source = source;
    }

    /** 构建树 */
    public abstract ITree<T, V> build() throws Exception;

    /** 合并树 */
    public abstract ITree<T, V> combine(ITree<T, V> otherTree) throws Exception;
    
    /** 匹配树，返回匹配结果 */
    public abstract Map<? extends ITreeNode<T, V>, ? extends ITreeNode<T, V>> getMatchTreeNodes(ITree<T, V> otherTree) throws Exception;

    /** 合并多棵树 */
    public abstract ITree<T, V> combine(List<ITree<T, V>> otherTrees) throws Exception;

    public List<ITreeNode<T, V>> getChilds()
    {
        if (childs == null)
        {
            childs = new ArrayList<ITreeNode<T, V>>();
        }
        return childs;
    }

    public T getSource()
    {
        return source;
    }

    /**
     * 递归获取所有节点
     * @return
     */
    public List<? extends ITreeNode<T, V>> recursionGetTreeNodes()
    {
        if (childs == null || childs.isEmpty())
        {
            return null;
        }
        List<ITreeNode<T, V>> result = new ArrayList<ITreeNode<T, V>>();
        for (ITreeNode<T, V> iTreeNode : childs)
        {
            recursionGetTreeNodesImpl(result, iTreeNode);
        }
        return result;
    }

    public void setChilds(List<ITreeNode<T, V>> childs)
    {
        this.childs = childs;
    }

    public void setSource(T source)
    {
        this.source = source;
    }

    /** 将自身转成DataTable */
    public abstract DataTable toDataTable() throws Exception;

    private void recursionGetTreeNodesImpl(List<ITreeNode<T, V>> result, ITreeNode<T, V> node)
    {
        result.add(node);
        List<ITreeNode<T, V>> childs = node.getChildren();
        if (childs == null || childs.isEmpty())
        {
            return;
        }
        for (ITreeNode<T, V> iTreeNode : childs)
        {
            recursionGetTreeNodesImpl(result, iTreeNode);
        }
    }
}
